package main

import "fmt"

// 自定义类型
type MyInt int

// 类型别名
type youuInt = int

// 结构体

type person struct {
	name   string
	age    int
	gender string
	hobby  []string
}

// 指针类型结构体
type pson struct {
	name string
	age  int
	new  bool
}

func main() {
	var n MyInt
	var m youuInt
	n = 100
	println(n)
	m = 100
	println(m)

	var c rune // rune 内置类型别名 相当于int32
	c = '中'
	println(c)

	var p person
	p.name = "zhoulin"
	p.age = 24
	p.gender = "男"
	p.hobby = []string{"篮球", "足球", "双色球"}
	fmt.Println(p)
	//访问变量p的字段
	fmt.Printf("%T\n", p)
	fmt.Println(p.name)
	// 匿名结构体
	var s struct {
		x string
		y int
	}
	s.x = "hahah"
	s.y = 10
	fmt.Printf("%T\n value:%v\n", s, s)

	var a pson
	a.name = "hahhaha"
	a.age = 10
	ss(a)
	sss(&a) // 根据内存地址找到那个原来的变量， 修改的是原来的变量
	fmt.Printf("%T\n value:%v\n", a, a)

	var p2 = new(pson) // 声明对应返回基本类型
	p2.age = 40
	fmt.Println(p2)
	ppp := newPerson("元帅", 18)
	fmt.Println(ppp)

	newPerson("元帅", 18)
}

func ss(a pson) {
	a.new = true
	fmt.Printf("%T\n value:%v\n", a, a)
}

func sss(a *pson) {
	(*a).new = false
	a.new = true // 语法糖， 自动根据指针修改值
	fmt.Printf("%T\n value:%v\n", a, a)

	var p3 = person{
		name:   "zhang",
		gender: "nan",
	}
	fmt.Printf("%T\n value:%v\n", p3, p3)
	//p4 := &person{
	//	"zhang",
	//	"nan",
	//}
	//fmt.Printf("%T\n value:%v\n", p4, p4)
	type x struct {
		a int8
		b int8
		c int8
	}

	m := &x{
		a: int8(10),
		b: int8(20),
		c: int8(40),
	}
	fmt.Printf("%T\n value:%v\n", m, m)
}

// 标识符： 变量名 函数名 方法名 首字母大写（表示外部可以访问，暴露的）
type dog struct {
	name string
}

// 构造函数：约定成俗用new开头
// 返回的是结构体还是结构体指针
// 当结构体比较大的时候尽量用结构体指针，减少程序内存开销
func newPerson(name string, age int) *dog {
	return &dog{
		name: name,
	}
}

// 方法作用于特定类型的函数
// 接收者表示的是调用改发方法的具体类型变量，多用类型名首字母小写表示
func (d dog) wang() {
	fmt.Printf("%T\n value:%v\n", d, d)
	m := myInt(100)
	m.hello()
}

// 给定义类型添加方法
// 不能给别的包里面的类型添加方法，只能给自己包里面添加方法
type myInt int

func (m myInt) hello() {
	fmt.Println(1)
}

// 常遇到的问题

//1.自定义类型

// / 初始化
func a() {
	type Info struct {
		name string
		age  int
	}
	s := Info{
		"张三",
		20,
	}
	s1 := []int{1, 2, 3, 4}
	s2 := map[string]int{
		"s":  10,
		"s1": 20,
	}

}

// 为什么要有构造函数  值类型和指针类型

func nnnn(x string, y int) *person {
	return &person{
		name: x,
		age:  y,
	}
}

func nnn(x string, y int) person {
	return person{
		name: x,
		age:  y,
	}
}

// 匿名字段 不常用
type ppp struct {
	string
	int
}

func init() {
	p1 := ppp{
		"周林",
		900000,
	}
	fmt.Println(p1)
	fmt.Println(p1.string, p1.int)
}

// 嵌套结构体

type aaa struct {
	name    string
	age     int
	address // 匿名嵌套 address 写的时候注意字段不能冲突（两个结构体中不能出现相同字段）
}

type company struct {
	name string
	address
}

type address struct {
	province string
	city     string
}

func init() {
	p1 := aaa{
		name: "123",
		age:  12,
		address: address{
			province: "上海",
			city:     "闵行区",
		},
	}
	fmt.Println(p1)
	fmt.Println(p1.name, p1.address.city)
	fmt.Println(p1.city)
}

// 结构体模拟实现其他语言中的继承

type animal struct {
	name string
}

// 狗

type dogs struct {
	feet   uint8
	animal // animal拥有的方法，dog此时也有了
}

// 给animal实现一个移动的方法

func (a animal) move() {
	fmt.Printf("%s会动！", a.name)
}

func (d dogs) wangs() {
	fmt.Printf("%s在叫：汪汪汪！", d.name)
}

func init() {
	d1 := dogs{
		animal: animal{name: "zhoulin"},
		feet:   4,
	}
	fmt.Println(d1)
	d1.wangs()
	d1.move()
}
